package cn.lsc.service.impl;

import cn.lsc.constants.RegisterConstant;
import cn.lsc.constants.RedisRegistConstant;
import cn.lsc.constants.RegisterPropertiesConstant;
import cn.lsc.domain.MessageSms;
import cn.lsc.dto.RedisRegisterDto;
import cn.lsc.enums.GlobaEnums;
import cn.lsc.exception.GlobaCustomException;
import cn.lsc.properties.RegisterProperties;
import cn.lsc.result.JSONResult;
import cn.lsc.service.IMessageSmsService;
import cn.lsc.service.IVerifyCodeService;
import cn.lsc.util.AssertUtil;
import cn.lsc.util.StrUtils;
import cn.lsc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IMessageSmsService iMessageSmsService;

    @Autowired
    private RegisterPropertiesConstant registerPropertiesConstant;
    @Autowired
    private RegisterProperties registerProperties;



    @Override
    public String getVerifyCode(String key) {
        //校验一波key值是否为空
        if(StringUtils.isEmpty(key)){
            throw  new GlobaCustomException("参数有误！");
        }
        //生成随机验证码
        String code = StrUtils.getComplexRandomString(4);
        //存入redis中，设置过期时间
        redisTemplate.opsForValue().set(key,code,3, TimeUnit.MINUTES);

        //生成一个base64字符串 并返回到请前端
        return VerifyCodeUtils.verifyCode(80,40,code);


    }
    //注册操作

    @Override
    public void smsCode(Map<String, String> map) {
        Date date = new Date();
        String phone = map.get("mobile");//电话号码
        String imageCode = map.get("imageCode");//图形验证码
        String imageCodeKey = map.get("imageCodeKey");//图形验证码对应得key
        // 1. 校验，参数不能为空
        AssertUtil.isPhone(phone,GlobaEnums.PHONE_FORMAT_ERROR);
        AssertUtil.isNotEmpty(imageCode,GlobaEnums.PARAM_IS_NULL_ERROR);
        AssertUtil.isNotEmpty(imageCodeKey,GlobaEnums.PARAM_IS_NULL_ERROR);

        String key=String.format(RedisRegistConstant.PHONE_REGISTER_PREFIX,phone);
        Object redisCode=redisTemplate.opsForValue().get(key);
        // 5.判断code是否存在
        String code = "";
        if (redisCode != null){
            // 将值进行拆分，获取到时间戳 code:时间戳
            RedisRegisterDto redisRegisterDto = (RedisRegisterDto) redisCode;
            // 判断是否过了1分钟
            if ((date.getTime() - redisRegisterDto.getDateTime()) < registerProperties.getInterval()){
                // 小于有人在搞事
                throw new GlobaCustomException(GlobaEnums.INTERVAL_ERROR);
            }
            code = redisRegisterDto.getCode();
        }else {
            // 如果redis中没有，那么说明用户没有发送过验证码，或者验证码已过期，那么重新生成一个
            code = StrUtils.getRandomString(registerProperties.getCodesize());
        }
        // 6.存入redis，过期时间5分钟
        RedisRegisterDto redisVal = new RedisRegisterDto(code, date.getTime());
        redisTemplate.opsForValue().set(key, redisVal, 600000, TimeUnit.MILLISECONDS);

        // 7.发送短信验证码，真实开发肯定是要发送短信的
        String hint = String.format(registerProperties.getSmshint(), code);
        log.info(hint);
        // 记录短信日志
        saveMessageSms(hint, date);



    }
    private void saveMessageSms(String hint, Date date) {
        // 8.记录smsMessage数据库
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(registerProperties.getTitle());
        messageSms.setContent(hint);
        messageSms.setSendTime(date);
        // 设置IP
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        // 获取请求体 request
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        // 得到IP
        String remoteAddr = request.getRemoteAddr();
        messageSms.setIp(remoteAddr);
        iMessageSmsService.insert(messageSms);
    }

    @Override
    public void binderSmsCode(Map<String, String> map) {
        String phone = map.get("phone");//电话号码

        // 1. 校验，参数不能为空
        if(StringUtils.isEmpty(phone)
        ){
            throw new GlobaCustomException("手机号不能为空");
        }
        // 2. 图形验证码校验


        /**
         * key: 手机号+业务键   业务键：最好是常量
         * value: code:时间戳
         * kty:value
         */
        // 4. 判断是否是第一次发送请求，或者是验证码过期  从redis中取
        Object value = redisTemplate.opsForValue().get(phone+RegisterConstant.WXBINDER);
        String code=null;
        // 4.1. 如果取不到，没有发送过，获取过期了， 直接生成一个新的验证码保存到redis
        if(value==null){
            code = StrUtils.getComplexRandomString(6);
        }else{
            // 4.2. 如果取到了。判断是否超过一分钟。
            String redisTime = value.toString().split(":")[1];
            Long ltime = Long.valueOf(redisTime);
            // 4.2.1： 如果没超过1分钟，直接提示用户，1分钟之内不能多次发送。
            if(System.currentTimeMillis()-ltime<1*60*1000){
                throw new GlobaCustomException("一分钟内不能发送多次！");
            }else{
                // 4.2.2： 如果超过了一分钟，刷新过期时间，
                code = value.toString().split(":")[0];
            }
        }

        // 4.2.2： 把code存入redisz中
        redisTemplate.opsForValue().set(phone+ RegisterConstant.WXBINDER,
                code+":"+System.currentTimeMillis(),
                3,TimeUnit.MINUTES);

        // 5. 发送短信给用户
        System.out.println("您的验证码为："+code+",请在三分钟之内使用");
        // SmsSendUtil.sendSms(phone,"您的验证码为："+code+",请在三分钟之内使用");


    }

    @Override
    public JSONResult RecommendationCode(Long userId) {
        String RC = StrUtils.getComplexRandomString(4);

        return JSONResult.success(userId,RC);
    }
}

